package com.platform.common.utils;

import com.aspose.words.Document;
import com.aspose.words.SaveFormat;
import freemarker.template.Configuration;
import freemarker.template.Template;
import org.apache.poi.ss.usermodel.Workbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.UUID;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * @Auther: Zhouxw
 * @Date: 2018-7-12 15:01
 * @Description: 公共下载
 */
public class DownloadUtils {
    private static final Logger log = LoggerFactory.getLogger(DownloadUtils.class);
    //配置信息
    private static Configuration configuration;
    //设置模板位置
    private static final String templateFolder = "/templates/";

    static {
        configuration = new Configuration();
        configuration.setDefaultEncoding("utf-8");
        configuration.setClassForTemplateLoading(DownloadUtils.class, templateFolder);
    }

    /**
     * @Auther: Zhouxw
     * @Date: 2018-9-18 15:11
     * @Description: delFlag 是否删除该文件
     */
    public static boolean download(String fileName, String diskPath, boolean delFlag, HttpServletRequest request, HttpServletResponse response) {
        InputStream bis = null;
        BufferedOutputStream out = null;
        // 获取输入流
        try {
            File file = new File(diskPath);
            if (!file.exists()) {
                return false;
            }
            bis = new BufferedInputStream(new FileInputStream(file));
            //配置响应
            configDownload(request, response, fileName);
            out = new BufferedOutputStream(response.getOutputStream());
            int len = 0;
            while ((len = bis.read()) != -1) {
                out.write(len);
                out.flush();
            }
            if (delFlag) {
                file.delete();
            }
        } catch (Exception e) {
            log.error("通用下载异常：{}", e);
            return false;
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    log.error("关闭流异常：{}", e);
                }
            }
            if (bis != null) {
                try {
                    bis.close();
                } catch (IOException e) {
                    log.error("关闭流异常：{}", e);
                }
            }
        }
        return true;
    }

    /**
     * @Auther: Zhouxw
     * @Date: 2018-9-25 14:59
     * @Description: 下载Mongo储存的文件
     */
    public static boolean downloadFromMongo(String fileName, InputStream in, HttpServletRequest request, HttpServletResponse response) {
        InputStream bis = null;
        BufferedOutputStream out = null;
        /* 获取输入流 */
        try {
            bis = new BufferedInputStream(in);
            //配置响应
            configDownload(request, response, fileName);
            out = new BufferedOutputStream(response.getOutputStream());
            int len = 0;
            while ((len = bis.read()) != -1) {
                out.write(len);
                out.flush();
            }
        } catch (Exception e) {
            log.error("下载Mongo文件异常：{}", e);
            return false;
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    log.error("关闭流异常：{}", e);
                }
            }
            if (bis != null) {
                try {
                    bis.close();
                } catch (IOException e) {
                    log.error("关闭流异常：{}", e);
                }
            }
        }
        return true;
    }

    /**
     * @Auther: Zhouxw
     * @Date: 2019-7-5 17:11
     * @Description: 下载流文件
     */
    public static boolean onLinePDF(String fileName, InputStream in, HttpServletRequest request, HttpServletResponse response) {
        InputStream bis = null;
        BufferedOutputStream out = null;
        /* 获取输入流 */
        try {
            bis = new BufferedInputStream(in);
            //配置响应
            configDownload(request, response, fileName, "inline");
            out = new BufferedOutputStream(response.getOutputStream());
            int len = 0;
            while ((len = bis.read()) != -1) {
                out.write(len);
                out.flush();
            }
        } catch (Exception e) {
            log.error("下载文件异常：{}", e);
            return false;
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    log.error("关闭流异常：{}", e);
                }
            }
            if (bis != null) {
                try {
                    bis.close();
                } catch (IOException e) {
                    log.error("关闭流异常：{}", e);
                }
            }
        }
        return true;
    }

    /**
     * @Auther: Lipf
     * @Date: 2018-11-1 16:34
     * @Description: 设置response头 为下载zip, 设置文件名. 应该在response写出之前被调用
     */
    public static void configDownload(HttpServletRequest request, HttpServletResponse response, String fileName) {
        configDownload(request, response, fileName, "attachment");
    }

    /**
     * @param inline attachment 提示下载 ，inline在线预览
     * @Auther: Zhouxw
     * @Date: 2018-10-9 11:27
     * @Description: 设置response头 为下载zip, 设置文件名. 应该在response写出之前被调用
     */
    public static void configDownload(HttpServletRequest request, HttpServletResponse response, String fileName, String inline) {
        String finalFileName = "";
        try {
            final String userAgent = request.getHeader("USER-AGENT").toLowerCase();
            if (userAgent != null) {
                if (userAgent.contains("msie") || (userAgent.indexOf("gecko") > 0 && userAgent.indexOf("rv:11") > 0)) {
                    finalFileName = URLEncoder.encode(fileName, "UTF-8");
                } else if (userAgent.contains("mozilla") || userAgent.contains("chrome")) {
                    finalFileName = new String(fileName.getBytes(), "ISO-8859-1");
                } else {
                    finalFileName = URLEncoder.encode(fileName, "UTF-8");
                }
            } else {
                finalFileName = fileName;
            }
        } catch (UnsupportedEncodingException e) {
            log.error("设置响应头异常：{}", e);
        }
        /* 这里设置一下让浏览器弹出下载提示框，而不是直接在浏览器中打开 */
        response.setHeader("Content-Disposition", inline + "; filename=" + finalFileName);
        //response.setContentType("multipart/form-data");
        response.setContentType(getContentType(finalFileName));
    }

    /**
     * @Auther: Zhouxw
     * @Date: 2018-10-9 11:26
     * @Description: 封装压缩文件的方法
     */
    public static void zipFile(File inputFile, ZipOutputStream zipoutputStream) {
        FileInputStream fis = null;
        BufferedInputStream bis = null;
        try {
            if (inputFile.exists()) { //判断文件是否存在
                if (inputFile.isFile()) {  //判断是否属于文件，还是文件夹
                    //创建输入流读取文件
                    fis = new FileInputStream(inputFile);
                    bis = new BufferedInputStream(fis);
                    //将文件写入zip内，即将文件进行打包
                    ZipEntry ze = new ZipEntry(inputFile.getName()); //获取文件名
                    zipoutputStream.putNextEntry(ze);
                    //写入文件的方法，同上
                    byte[] b = new byte[1024];
                    long l = 0;
                    while (l < inputFile.length()) {
                        int j = bis.read(b, 0, 1024);
                        l += j;
                        zipoutputStream.write(b, 0, j);
                    }
                } else {
                    //如果是文件夹，则使用穷举的方法获取文件，写入zip
                    File[] files = inputFile.listFiles();
                    for (int i = 0; i < files.length; i++) {
                        zipFile(files[i], zipoutputStream);
                    }
                }
            }
        } catch (Exception e) {
            log.error("压缩文件异常：{}", e);
        } finally {
            //关闭输入输出流
            if (null != fis) {
                try {
                    fis.close();
                } catch (IOException e) {
                    log.error("关闭流异常：{}", e);
                }
            }
            if (null != bis) {
                try {
                    bis.close();
                } catch (IOException e) {
                    log.error("关闭流异常：{}", e);
                }
            }
        }
    }

    /**
     * @param request
     * @param response
     * @param data     数据集
     * @param title    下载默认名称
     * @param ftlFile  模板名称
     * @throws IOException
     * @author: zhouxw
     * @date: 2018年5月16日 下午2:21:54
     * @Description: 根据ftl导出Word功能
     */
    public static void exportWord(
        HttpServletRequest request,
        HttpServletResponse response,
        Object data,
        String title,
        String ftlFile
    ) {
        File file = null;
        InputStream fin = null;
        ServletOutputStream out = null;
        try {
            Template freemarkerTemplate = configuration.getTemplate(ftlFile, "utf-8");
            //freemarkerTemplate
            // 调用工具类的createDoc方法生成Word文档
            file = createDoc(data, freemarkerTemplate);
            fin = new FileInputStream(file);

            // 设置浏览器以下载的方式处理该文件名
            String fileName = title + ".doc";
            // 配置响应
            configDownload(request, response, fileName);
            out = response.getOutputStream();
            byte[] buffer = new byte[512]; // 缓冲区
            int bytesToRead = -1;
            // 通过循环将读入的Word文件的内容输出到浏览器中
            while ((bytesToRead = fin.read(buffer)) != -1) {
                out.write(buffer, 0, bytesToRead);
            }
        } catch (IOException e) {
            log.error("导出Word异常：{}", e);
        } finally {
            if (fin != null) {
                try {
                    fin.close();
                } catch (IOException e) {
                    log.error("关闭流异常：{}", e);
                }
            }
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    log.error("关闭流异常：{}", e);
                }
            }
            if (file != null) {
                // 删除临时文件
                file.delete();
            }
        }
    }

    /**
     * @Auther: Zhouxw
     * @Date: 2019-4-9 9:32
     * @Description: 在线导出PDF（生成的word直接转PDF）
     */
    public static String exportPDF(
        Object data,
        String ftlFile
    ) {
        String randomId = null;
        File file = null;
        InputStream fin = null;
        FileOutputStream os = null;
        try {
            Template freemarkerTemplate = configuration.getTemplate(ftlFile, "utf-8");
            // 调用工具类的createDoc方法生成Word文档
            file = createDoc(data, freemarkerTemplate);
            fin = new FileInputStream(file);

            if (!Doc2Pdf.getLicense()) {          // 验证License 若不验证则转化出的pdf文档会有水印产生
                return null;
            }
            long old = System.currentTimeMillis();
            randomId = UUID.randomUUID().toString();
            File tempFile = new File(randomId + ".pdf");
            os = new FileOutputStream(tempFile);
            Document doc = new Document(fin);                    //Address是将要被转化的word文档
            doc.save(os, SaveFormat.PDF);    //全面支持DOC, DOCX, OOXML, RTF HTML, OpenDocument, PDF, EPUB, XPS, SWF 相互转换
            long now = System.currentTimeMillis();
            System.out.println("共耗时：" + ((now - old) / 1000.0) + "秒");  //转化用时

        } catch (Exception e) {
            log.error("导出Word异常：{}", e);
        } finally {
            if (fin != null) {
                try {
                    fin.close();
                } catch (IOException e) {
                    log.error("关闭流异常：{}", e);
                }
            }
            if (os != null) {
                try {
                    os.close();
                } catch (IOException e) {
                    log.error("关闭流异常：{}", e);
                }
            }
            if (file != null) {
                // 删除临时文件
                file.delete();
            }
        }
        return randomId;
    }

    /**
     * @param data
     * @param template
     * @return File
     * @author: zhouxw
     * @date: 2018年5月16日 下午2:19:58
     * @Description: 生成临时word文件
     */
    private static File createDoc(Object data, Template template) {
        String time = DateUtils.getYYYYMMddHHmmss();
        String name = time + (int) ((Math.random() * 9 + 1) * 1000) + ".doc";
        File f = new File(name);
        Template t = template;
        Writer w = null;
        try {
            // 这个地方不能使用FileWriter因为需要指定编码类型否则生成的Word文档会因为有无法识别的编码而无法打开
            w = new OutputStreamWriter(new FileOutputStream(f), "utf-8");
            t.process(data, w);
        } catch (Exception e) {
            log.error("生成Word文件异常：{}", e);
        } finally {
            if (w != null) {
                try {
                    w.close();
                } catch (IOException e) {
                    log.error("关闭流异常：{}", e);
                }
            }
        }
        return f;
    }

    /**
     * @Auther: Zhouxw
     * @Date: 2018-10-23 8:55
     * @Description: 对导出word内容特殊字符处理
     */
    public static String specialCharacterForContent(String str) {
        log.info("特殊字符处理前：{}", str);
        String result = str.replace(";", "；")
            .replace(",", "，")
            .replace("&", "&amp;")
            .replace("<", "&lt;");
        log.info("特殊字符处理后：{}", result);
        return result;
    }

    /**
     * @Auther: Zhouxw
     * @Date: 2018-10-23 8:55
     * @Description: 对导出文件名称特殊字符处理(参照windows对文件名特殊字符处理)
     */
    public static String specialCharacterForTitle(String str) {
        log.info("特殊字符处理前：{}", str);
        String result = str.replace(":", "：")
            .replace("/", "")
            .replace("\\", "")
            .replace("?", "？")
            .replace(",", "，")
            .replace("*", "")
            .replace("<", "《")
            .replace(">", "》")
            .replace("\"", "'")
            .replace("|", "")
            .replace(";", "")
            .replace("&amp", "")
            .replace("&lt", "");
        log.info("特殊字符处理后：{}", result);
        return result;
    }

    /**
     * @Auther: Lipf
     * @Date: 2018-11-1 16:00
     * @Description: 根据“文件名的后缀”获取文件内容类型（而非根据File.getContentType()读取的文件类型）
     */
    public static String getContentType(String returnFileName) {
        String contentType = "application/octet-stream";
        if (returnFileName.lastIndexOf(".") < 0)
            return contentType;
        returnFileName = returnFileName.toLowerCase();
        returnFileName = returnFileName.substring(returnFileName.lastIndexOf(".") + 1);
        if (returnFileName.equals("html") || returnFileName.equals("htm") || returnFileName.equals("shtml")) {
            contentType = "text/html";
        } else if (returnFileName.equals("apk")) {
            contentType = "application/vnd.android.package-archive";
        } else if (returnFileName.equals("sis")) {
            contentType = "application/vnd.symbian.install";
        } else if (returnFileName.equals("sisx")) {
            contentType = "application/vnd.symbian.install";
        } else if (returnFileName.equals("exe")) {
            contentType = "application/x-msdownload";
        } else if (returnFileName.equals("msi")) {
            contentType = "application/x-msdownload";
        } else if (returnFileName.equals("css")) {
            contentType = "text/css";
        } else if (returnFileName.equals("xml")) {
            contentType = "text/xml";
        } else if (returnFileName.equals("gif")) {
            contentType = "image/gif";
        } else if (returnFileName.equals("jpeg") || returnFileName.equals("jpg")) {
            contentType = "image/jpeg";
        } else if (returnFileName.equals("js")) {
            contentType = "application/x-javascript";
        } else if (returnFileName.equals("atom")) {
            contentType = "application/atom+xml";
        } else if (returnFileName.equals("rss")) {
            contentType = "application/rss+xml";
        } else if (returnFileName.equals("mml")) {
            contentType = "text/mathml";
        } else if (returnFileName.equals("txt")) {
            contentType = "text/plain";
        } else if (returnFileName.equals("jad")) {
            contentType = "text/vnd.sun.j2me.app-descriptor";
        } else if (returnFileName.equals("wml")) {
            contentType = "text/vnd.wap.wml";
        } else if (returnFileName.equals("htc")) {
            contentType = "text/x-component";
        } else if (returnFileName.equals("png")) {
            contentType = "image/png";
        } else if (returnFileName.equals("tif") || returnFileName.equals("tiff")) {
            contentType = "image/tiff";
        } else if (returnFileName.equals("wbmp")) {
            contentType = "image/vnd.wap.wbmp";
        } else if (returnFileName.equals("ico")) {
            contentType = "image/x-icon";
        } else if (returnFileName.equals("jng")) {
            contentType = "image/x-jng";
        } else if (returnFileName.equals("bmp")) {
            contentType = "image/x-ms-bmp";
        } else if (returnFileName.equals("svg")) {
            contentType = "image/svg+xml";
        } else if (returnFileName.equals("jar") || returnFileName.equals("var")
            || returnFileName.equals("ear")) {
            contentType = "application/java-archive";
        } else if (returnFileName.equals("doc")) {
            contentType = "application/msword";
        } else if (returnFileName.equals("pdf")) {
            contentType = "application/pdf";
        } else if (returnFileName.equals("rtf")) {
            contentType = "application/rtf";
        } else if (returnFileName.equals("xls")) {
            contentType = "application/vnd.ms-excel";
        } else if (returnFileName.equals("ppt")) {
            contentType = "application/vnd.ms-powerpoint";
        } else if (returnFileName.equals("7z")) {
            contentType = "application/x-7z-compressed";
        } else if (returnFileName.equals("rar")) {
            contentType = "application/x-rar-compressed";
        } else if (returnFileName.equals("swf")) {
            contentType = "application/x-shockwave-flash";
        } else if (returnFileName.equals("rpm")) {
            contentType = "application/x-redhat-package-manager";
        } else if (returnFileName.equals("der") || returnFileName.equals("pem")
            || returnFileName.equals("crt")) {
            contentType = "application/x-x509-ca-cert";
        } else if (returnFileName.equals("xhtml")) {
            contentType = "application/xhtml+xml";
        } else if (returnFileName.equals("zip")) {
            contentType = "application/zip";
        } else if (returnFileName.equals("mid") || returnFileName.equals("midi")
            || returnFileName.equals("kar")) {
            contentType = "audio/midi";
        } else if (returnFileName.equals("mp3")) {
            contentType = "audio/mpeg";
        } else if (returnFileName.equals("ogg")) {
            contentType = "audio/ogg";
        } else if (returnFileName.equals("m4a")) {
            contentType = "audio/x-m4a";
        } else if (returnFileName.equals("ra")) {
            contentType = "audio/x-realaudio";
        } else if (returnFileName.equals("3gpp")
            || returnFileName.equals("3gp")) {
            contentType = "video/3gpp";
        } else if (returnFileName.equals("mp4")) {
            contentType = "video/mp4";
        } else if (returnFileName.equals("mpeg")
            || returnFileName.equals("mpg")) {
            contentType = "video/mpeg";
        } else if (returnFileName.equals("mov")) {
            contentType = "video/quicktime";
        } else if (returnFileName.equals("flv")) {
            contentType = "video/x-flv";
        } else if (returnFileName.equals("m4v")) {
            contentType = "video/x-m4v";
        } else if (returnFileName.equals("mng")) {
            contentType = "video/x-mng";
        } else if (returnFileName.equals("asx") || returnFileName.equals("asf")) {
            contentType = "video/x-ms-asf";
        } else if (returnFileName.equals("wmv")) {
            contentType = "video/x-ms-wmv";
        } else if (returnFileName.equals("avi")) {
            contentType = "video/x-msvideo";
        }
        return contentType;
    }


	/* public static void downExcel(
		        HttpServletRequest request,
		        HttpServletResponse response,
		        Object data,
		        InputStream tempInputStream,
		        String downName
		    ){

		 try {
	            //response.setHeader("Content-type","application/vnd.ms-excel");
	            // 解决导出文件名中文乱码
	            //response.setCharacterEncoding("UTF-8");
	            //response.setHeader("Content-Disposition","attachment;filename="+new String(downName.getBytes("UTF-8"),"ISO-8859-1")+".xls");
	             configDownload(request,response,downName);
	            // 模板导出Excel
	            Workbook wb = ExcelHelper.getWorkBook((List<? extends Object[]>) data,tempInputStream);
	            wb.write(response.getOutputStream());
	        } catch (IOException e) {
	            e.printStackTrace();
	        }*/

    public static void downExcel(
        HttpServletRequest request,
        HttpServletResponse response,
        Object data,
        InputStream tempInputStream,
        String downName,
        Workbook wb
    ) {

        try {
            configDownload(request, response, downName);
            wb.write(response.getOutputStream());
        } catch (IOException e) {
            e.printStackTrace();
        }


    }


}
